﻿using System;
using System.IO;
using System.Linq.Expressions;
using NMock2;
using NMock2.Monitoring;
using NMock2.Syntax;

namespace DotNetNeural.Test.Helpers
{
    public static class NMockExtensions
    {
        public static IArgumentSyntax Method<TType, TResult>(this IMethodSyntax ms, Expression<Func<TType, TResult>> expr)
        {
            LambdaExpression le = expr as LambdaExpression;
            MethodCallExpression mc = le.Body as MethodCallExpression;

            var result = GetMethod(ms, mc);

            if (result == null)
            {
                UnaryExpression ue = le.Body as UnaryExpression;
                if (ue != null)
                {
                    mc = ue.Operand as MethodCallExpression;
                    result = GetMethod(ms, mc);
                }
            }

            return result;
        }

        private static IArgumentSyntax GetMethod(IMethodSyntax ms, MethodCallExpression mexpr)
        {
            if (mexpr != null)
            {
                var mi = mexpr.Method;
                if (mi != null)
                {
                    return ms.Method(mi);
                }
            }

            return null;
        }

        public static void Will<T>(this IActionSyntax asx, Func<T> func)
        {
            asx.Will(new CustomAction<T>(func));
        }

        public static IMatchSyntax GetProperty<TProp>(this IMethodSyntax ms, Expression<Func<TProp>> expr)
        {
            var mexpr = expr.Body as MemberExpression;
            if ( mexpr != null ){
                var memberInfo = mexpr.Member;
                return ms.GetProperty(memberInfo.Name);
            }

            return null;
        }
    }

    internal class CustomAction<T> : IAction
    {
        public Func<T> Func { get; private set; }

        public CustomAction(Func<T> func)
        {
            if (func == null)
                throw new NullReferenceException("Illegal null-reference func");

            Func = func;
        }

        #region IInvokable Members

        public void Invoke(Invocation invocation)
        {
            invocation.Result = Func();
        }

        #endregion

        #region ISelfDescribing Members

        public void DescribeTo(TextWriter writer)
        {
            writer.Write("Invoking " + Func.ToString());
        }

        #endregion
    }
}
